package com.znxz.hzqiuxm.ziniublog.global.security;

import com.znxz.hzqiuxm.ziniublog.global.common.SysConst;
import com.znxz.hzqiuxm.ziniublog.global.config.PropertiesValue;
import com.znxz.hzqiuxm.ziniublog.user.domain.valobj.JwtUser;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;

/**
 * Copyright © 2018年 ziniuxiaozhu. All rights reserved.
 *
 * @Author 临江仙 hzqiuxm@163.com
 * 自定义JWT认证过滤器,该类继承自OncePerRequestFilter(BasicAuthenticationFilter)，在doFilterInternal方法中，
 * 从http头的Authorization项读取token数据，然后用Jwts包提供的方法校验token的合法性。
 * 如果校验通过，就认为这是一个取得授权的合法请求
 * @Date 2018/8/31 17:06
 */
@Slf4j
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter{

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private PropertiesValue propertiesValue;


    /**
     * JWT过滤器，有token直接验证token有效性(能够正常解析)，无效或没有时跳转到用户名密码登录
     * @param request
     * @param response
     * @param filterChain
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doFilterInternal (HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        log.info("==================doFilterInternal begin ====================");
        final String servletPath = request.getServletPath();
        if(!servletPath.startsWith("/auth")){
            String authToken = request.getHeader(propertiesValue.getTokenHeader());
            if (authToken != null && !"null".equals(authToken)) {
                log.info("token is :{}", authToken);
                JwtUser jwtUser = jwtTokenUtil.token2jwtuser(authToken);
                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(jwtUser, null, jwtUser.getAuthorities());
                SecurityContextHolder.getContext().setAuthentication(authenticationToken);

                if (jwtTokenUtil.canTokenBeRefreshed(jwtUser.getExpiration())) {
                    response.addHeader(propertiesValue.getTokenHeader(), jwtTokenUtil.generateToken(jwtUser));
                }
            }
        }
        log.info("to be continue ........");
        filterChain.doFilter(request, response);
    }

    public UsernamePasswordAuthenticationToken getAuthentication(String authToken){

        Claims claims = jwtTokenUtil.getClaimsFromToken(authToken);
        String user = claims.getSubject();
        if(null != claims){
            ArrayList<GrantedAuthority> authorities = new ArrayList<>();
            ArrayList roles = (ArrayList) claims.get(SysConst.ROLES);
            for (int i = 0; i <roles.size(); i++) {
                Map<String,String> role = (Map<String, String>) roles.get(i);
                GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.get(SysConst.AUTHORITY));
                authorities.add(grantedAuthority);
            }

            log.info("getAuthentication result :{} " + authorities);
            return new UsernamePasswordAuthenticationToken(user, null, authorities);
        }

        return null;


    }
}
